/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package umat.beans;

/**
 *
 * @author Tudor
 */
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.model.TreeNode;

/**
 * 
 * @author Tudor
 */
public class Node implements TreeNode, Serializable {

    /**
     * Class for the nodes of the tree
     */
    public static final String DEFAULT_TYPE = "default"; //used by primefaces
    private String type;                                 //see above
    private Object data;                                 //used as name of the node
    private List<TreeNode> children;                     //children
    private ArrayList<Field> fields;                     //fields, implemented as arraylist
    private TreeNode parent;                             //parent
    private boolean expanded;                            //for GUI purposes
    private boolean selected;                            //for GUI purposes
    private boolean selectable = true;                   //for GUI purposes
    private String fieldName, fieldType;                 //temporary values for field data
    private Field[] selectedFields;

    /**
     * Sets the name of the node as "New node", best used for testing
     */
    public Node() {
        this.type = "default";
        this.children = new ArrayList();
        this.fields = new ArrayList();
        this.data = "New Node";
        this.fieldName = "";
        this.fieldType = "String";
    }

    /**
     * Automatically ads the node to the parents child list and sets the parent
     * variable as the nodes parent
     * @param data Name of the node
     * @param parent The parent
     */
    public Node(Object data, TreeNode parent) {
        this.type = "default";
        this.data = data;
        this.children = new ArrayList();
        this.fields = new ArrayList();
        this.parent = parent;
        this.fieldName = "";
        this.fieldType = "";
        if (this.parent != null) {
            this.parent.getChildren().add(this);
        }
    }

    /**
     * Automatically ads the node to the parents child list and sets the parent
     * variable as the nodes parent
     * @param type Used for sorting the nodes in the GUI
     * @param data The name of the node
     * @param parent The parent of the node
     */
    public Node(String type, Object data, TreeNode parent) {
        this.type = type;
        this.data = data;
        this.children = new ArrayList();
        this.fields = new ArrayList();
        this.parent = parent;
        this.fieldName = "";
        this.fieldType = "";
        if (this.parent != null) {
            this.parent.getChildren().add(this);
        }
    }

    /**
     * Returns the type of the node
     * @return
     */
    @Override
    public String getType() {
        return this.type;
    }

    /**
     * Returns the name of the node
     * @return
     */
    @Override
    public Object getData() {
        return this.data;
    }

    /**
     * Returns the child list
     * @return
     */
    @Override
    public List<TreeNode> getChildren() {
        return this.children;
    }

    /**
     * Returns the parent of the node
     * @return
     */
    @Override
    public TreeNode getParent() {
        return this.parent;
    }

    /**
     * Returns the number of children the node has
     * @return
     */
    @Override
    public int getChildCount() {
        return this.children.size();
    }

    /**
     * Getter for the variable used to create a new node, specifically, the name of the field
     * @return
     */
    public String getFieldName() {
        return fieldName;
    }

    /**
     * Getter for the variable used to create a new node, specifically, the type of the field
     * @return
     */
    public String getFieldType() {
        return fieldType;
    }

    /**
     * Returns the number of fields this node has
     * @return
     */
    public int getFieldSize() {
        return fields.size();
    }

    /**
     * Returns the fields of the node
     * @return
     */
    public ArrayList<Field> getFields() {
        if (fields != null) {
            return fields;
        }
        printMessage("No fields");
        return null;
    }

    /**
     * Setter for the node type
     * @param type
     */
    public void setType(String type) {
        this.type = type;
    }

    /**
     * Setter for the nodes name
     * @param data
     */
    public void setData(Object data) {
        this.data = data;
    }

    /**
     * Sets if the node can be selected in the GUI or not
     * @param selectable
     */
    @Override
    public void setSelectable(boolean selectable) {
        this.selectable = selectable;
    }

    /**
     * Sets the field list of the node
     * @param children
     */
    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

    /**
     * Sets the parent of the node
     * @param parent
     */
    @Override
    public void setParent(TreeNode parent) {
        if (this.parent != null) {
            this.parent.getChildren().remove(this);
        }
        this.parent = parent;
        if (this.parent != null) {
            this.parent.getChildren().add(this);
        }
    }

    /**
     * Returns true if the node is expanded in the GUI, false otherwise
     * @return
     */
    @Override
    public boolean isExpanded() {
        return this.expanded;
    }

    /**
     * `Returns true if the node is expanded in the GUI, false otherwise
     * @param expanded
     */
    @Override
    public void setExpanded(boolean expanded) {
        this.expanded = expanded;
    }

    /**
     * 
     * @param fieldName
     */
    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    /**
     * Sets the type for the new field to be added
     * @param fieldType
     */
    public void setFieldType(String fieldType) {
        this.fieldType = fieldType;
    }

    /**
     * Sets the fields of the node
     * @param fields
     */
    public void setFields(ArrayList<Field> fields) {
        this.setFields(fields);
    }

    /**
     * Returns true if the node is selected in the GUI, false otherwise
     * @return
     */
    @Override
    public boolean isSelected() {
        return this.selected;
    }

    /**
     * Set if the node is selected or not
     * @param value
     */
    @Override
    public void setSelected(boolean value) {
        this.selected = value;
    }

    /**
     * Returns true if the node can be selected, false otherwise
     * @return
     */
    @Override
    public boolean isSelectable() {
        return this.selectable;
    }

    /**
     * Returns true if the node has no sub-nodes
     * @return
     */
    @Override
    public boolean isLeaf() {
        if (this.children == null) {
            return true;
        }
        return this.children.isEmpty();
    }

    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + (this.data == null ? 0 : this.data.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Node other = (Node) obj;
        if (this.data == null) {
            if (other.data != null) {
                return false;
            }
        } else if (!this.data.equals(other.data)) {
            return false;
        }
        return true;
    }

    /**
     * Adds a new field to the node, with fieldName and fieldType as parameters
     */
    public void addField() {
        fields.add(new Field(fieldName, fieldType));
       // printMessage("Added field " + fieldType + " " + fieldName + " to " + data.toString());
        fieldName = null;
    }

    public void deleteField() {
        if (getSelectedFields().length > 0) {
            for (Field f : getSelectedFields()) {
                fields.remove(f);
            }
            if (getSelectedFields().length > 1) {
                printMessage("Deleted " + getSelectedFields().length + " fields");
            } else {
                printMessage("Deleted one field");
            }
        } else {
            printMessage("Nothing selected");
        }
    }

    public void deleteAllFields() {
        if (fields.size() > 0) {
            fields.clear();
            setSelectedFields(null);
            printMessage("All nodes deleted");
        } else {
            printMessage("Nothing to delete");
        }
    }

    public void printMessage(String message) {
        FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_INFO, "Selected", message);
        FacesContext.getCurrentInstance().addMessage(null, m);
    }

    @Override
    public String toString() {
        if (this.data != null) {
            return this.data.toString();
        }
        return super.toString();
    }

    /**
     * @return the selectedFields
     */
    public Field[] getSelectedFields() {
        return selectedFields;
    }

    /**
     * @param selectedFields the selectedFields to set
     */
    public void setSelectedFields(Field[] selectedFields) {
        this.selectedFields = selectedFields;
    }
}





